//@author A0105543N
#include "ES.h"

ES::ES()
{
	curRecord = new Record();
	forTrash = new Trash();
	mySearch = new Search();

	string date;
	double totalExpens, income;
	ifstream infile("Figure.txt");
	if (!infile) {                            //First time use. Set up all the text files to store data.
		ofstream dataStorage("Expense.txt");
		ofstream payment("Payment.txt");
		ofstream Figure("Figure.txt");
		dataStorage.close();
		Figure.close();
	}
	else {									//otherwise retrieve existing data from data storage file.
		infile >> income >> totalExpens;
		curRecord -> getTrace() -> initialize(income, totalExpens);
		curRecord -> setCategory();
	}
	infile.close();
}

void ES::deleteExpCat()
{
	int deleteID;
	string category;
	if (curRecord ->deleteExp(deleteID,category))         //delete the expense category at position deleteID  
		forTrash -> add_ExpCategory(deleteID,category);
}

void ES::deletePayCat()
{
	int deleteID;
	string category;
	if (curRecord -> deletePay(deleteID,category))      //delete the payment category at position deleteID
		forTrash -> add_PayCategory(deleteID,category);
}

void ES::updateFigure()
{
	ofstream outfile("Figure.txt");
	outfile << fixed << setprecision(2) << curRecord -> getTrace() -> gettotalPayment() <<' ';
	outfile.flush();
	outfile << fixed << setprecision(2) << curRecord -> getTrace() -> gettotalXpens() << ' ';
	outfile.flush();
	outfile.close();
	curRecord -> saveExit();       //update category into text file.
}

void ES::undo()
{
	int operation;
	streampos address;
	operation = forTrash -> getOperation();
	
	if ( !operation ) cout << "Undo is not available!\n";
	else {
	if (operation == 1){                          //last operation is payment 
		mySearch -> SearchFile("Payment.txt");
		curRecord -> getTrace() -> deleteTrace(forTrash -> getNewPayment());   //update total payment.
		PaymentItem emptyPayment;
		address = mySearch -> internalSearch(forTrash -> getNewPayment(),emptyPayment);
		curRecord -> updateItem(address, forTrash -> getOriginPayment());     
	}

	else if (operation == -1){                  //last operation is expense
		mySearch -> SearchFile("Expense.txt");
		curRecord -> getTrace() -> deleteTrace(forTrash -> getNewExpense());
		XpensItem emptyExpense;
		address = mySearch -> internalSearch(forTrash -> getNewExpense(),emptyExpense);
		curRecord -> updateItem(address, forTrash -> getOriginExpense());
	}

	else if (operation == 2){                 //last operation is delete payment category
		int ID;
		string category;
		forTrash -> getUndoPayCategory(ID, category);
		curRecord -> addPayCat(ID, category);
	}
	else if (operation == -2){                   //last operation is delete expense category
		int ID;
		string category;
		forTrash -> getUndoExpCategory(ID, category);
		curRecord -> addExpCat(ID, category);
	}
	}
}

void ES::redo()
{
	int operation;
	streampos address;
	operation = forTrash -> getRedoOperation();
	if (!operation) cout << "Redo is not available!\n";
	else {
	    if (operation == 1){
		mySearch -> SearchFile("Payment.txt");
		PaymentItem emptyPayment;
		curRecord -> getTrace() -> deleteTrace(forTrash -> getRedoOriginPayment());
		address = mySearch -> internalSearch(forTrash -> getRedoOriginPayment(),emptyPayment);
		curRecord -> updateItem(address, forTrash -> getRedoNewPayment());
	}
	    else if (operation == -1){
		mySearch -> SearchFile("Expense.txt");
		XpensItem emptyExpense;
		curRecord -> getTrace() -> deleteTrace(forTrash -> getRedoOriginExpense());
		address = mySearch -> internalSearch(forTrash -> getRedoOriginExpense(),emptyExpense);
		curRecord -> updateItem(address, forTrash -> getRedoNewExpense());
	}
	else if (operation == 2){
		int ID;
		string category;
		forTrash -> getRedoPayCategory(ID, category);
		curRecord -> deletePayCat(ID);
	}
	else if (operation == -2){
		int ID;
		string category;
		forTrash -> getRedoExpCategory(ID, category);
		curRecord -> deleteExpCat(ID);
	}	
	}
}

void ES::createExpense()
{
	XpensItem thisItem, emptyItem;
	if (curRecord -> createItem(thisItem)) {             //expense record may not be successful
		forTrash -> addOperation(-1);                    //update last operation
		forTrash -> add_Expense(emptyItem, thisItem);    
	}
}

void ES::createPayment()
{
	PaymentItem thisItem, emptyItem;
	if (curRecord -> createItem(thisItem)) {          //payment record may not be successful
		forTrash -> addOperation(1);
		forTrash -> add_Payment(emptyItem, thisItem);
	}
}

void ES::ExpensePowerSearch()
{
	XpensItem emptyItem;
	mySearch -> SearchFile("Expense.txt");         //search in expense file
	mySearch -> powerSearch();
	mySearch -> Print(emptyItem);
}

void ES::PaymentPowerSearch()
{
	PaymentItem emptyItem;
	mySearch -> SearchFile("Payment.txt");             //search in payment file
	mySearch -> powerSearch();
	mySearch -> Print(emptyItem);
}
void ES::updateExpense(int updateID)
{
	XpensItem newItem, originItem;
	while (updateID > mySearch -> numOfItems() || updateID < 1){   //check for validity of update index
		cout << "Invalid updateID. Please input a valid deleteID. Press 0 to exit. \n";
		cin >> updateID;
		if (updateID == 0) return;
	}
	updateID-=1;
	if (curRecord -> updateRecord(mySearch -> getAddress(updateID), newItem)) {
		mySearch -> SearchFile("Expense.txt");
		mySearch -> getItem(updateID, originItem);    //find the address where to find the current item
		curRecord -> getTrace() -> deleteTrace(originItem);
		curRecord -> updateItem(mySearch -> getAddress(updateID), newItem); //replace it with newItem, newItem is read in record class
		forTrash -> addOperation(-1);
		forTrash -> add_Expense(originItem, newItem);
	}
}

void ES::updatePayment(int updateID)
{
	PaymentItem newItem, originItem;
	while (updateID > mySearch -> numOfItems() || updateID < 1){
		cout << "Invalid updateID. Please input a valid deleteID. Press 0 to exit. \n";
		cin >> updateID;
		if (updateID == 0) return;
	}
	updateID-=1;
	if (curRecord -> updateRecord(mySearch -> getAddress(updateID), newItem)) {
		mySearch -> SearchFile("Payment.txt");
		mySearch -> getItem(updateID, originItem);
		curRecord -> getTrace() -> deleteTrace(originItem);
		curRecord -> updateItem(mySearch -> getAddress(updateID), newItem);
		forTrash -> addOperation(1);
		forTrash -> add_Payment(originItem, newItem);
	}
}

void ES::deleteExpense(int deleteID)
{
	XpensItem emptyItem, originItem;
	mySearch -> SearchFile("Expense.txt");

	while (deleteID > mySearch -> numOfItems() || deleteID < 1){
		cout << "Invalid deleteID. Please input a valid deleteID. Press 0 to exit. \n";
		cin >> deleteID;
		if (deleteID == 0) return;
	}
	deleteID-=1;
	mySearch -> getItem(deleteID, originItem);
	curRecord -> getTrace() -> deleteTrace(originItem);
	curRecord -> updateItem(mySearch -> getAddress(deleteID), emptyItem);
	forTrash -> addOperation(-1);
	forTrash -> add_Expense(originItem, emptyItem);
}

void ES::deletePayment(int deleteID)
{
	PaymentItem emptyItem, originItem;
	mySearch -> SearchFile("Payment.txt");
	
	while (deleteID > mySearch -> numOfItems() || deleteID < 1){
		cout << "Invalid deleteID. Please input a valid deleteID. Press 0 to exit. \n";
		cin >> deleteID;
		if (deleteID == 0) return;
	}
	deleteID-=1;
	mySearch -> getItem(deleteID, originItem);
	curRecord -> getTrace() -> deleteTrace(originItem);
	curRecord -> updateItem(mySearch -> getAddress(deleteID), emptyItem);
	forTrash -> addOperation(1);
	forTrash -> add_Payment(originItem, emptyItem);
}

bool ES::TrackExpense(string date)
{
	while (true)
	{
		if (Helper::checkDate(date)) break; //check the validity of date, defensive coding
		cout << "Press 0 to exit.\n";
		getline(cin,date);
		if (date == "0")
			return false;
	}
	XpensItem emptyItem;
	mySearch -> SearchFile("Expense.txt");
	mySearch -> Day_total_CF(date, emptyItem); //emptyItem is passed in to indicate whether it's an expense or payment
	if (mySearch -> Print(emptyItem)) return true;
	return false;
}

bool ES::TrackPayment(string date)
{
	while (true)
	{
		if (Helper::checkDate(date)) break;
		cout << "Press 0 to exit.\n";
		getline(cin,date);
		if (date == "0")
			return false;
	}
	PaymentItem emptyItem;
	mySearch -> SearchFile("Payment.txt");
	mySearch -> Day_total_CF(date, emptyItem);
	if (mySearch -> Print(emptyItem)) return true;
	return false;
}
void ES::Alert()
{
	if (curRecord -> getTrace() -> gettotalXpens() > 0)
		if  ( curRecord -> getTrace() -> gettotalPayment() - curRecord -> getTrace() -> gettotalXpens() < 50)
		cout << "Caution! You have spent too much.\nYour total cash is less than 50 dollars!\n";
}

void ES::ReportDay(string date)
{
	while (true)
	{
		if (Helper::checkDate(date)) break;     //check for validity of date
		cout << "Press 0 to exit.\n";
		getline(cin,date);
		if (date == "0")
			return;
	}
	XpensItem emptyExpense;
	PaymentItem emptyPayment;

	mySearch -> SearchFile("Expense.txt");
	cout << "Your total expense on " << Helper::dayString(date) << " is "<< mySearch -> Day_total_CF(date, emptyExpense) << ".\n";

	mySearch -> SearchFile("Payment.txt");
	cout << "Your total payment on " << Helper::dayString(date) << " is "<< mySearch -> Day_total_CF(date, emptyPayment) << ".\n";

}

void ES::ReportMonth(int year, int month)
{
	while (year < 2010 || month < 0 || month >12 || year > 2100) {//check for validity of input year and month
		cout << "Input right year and month. Press 0 0 to exit.\n";
		cin >> year >> month;
		if (year == 0 && month == 0) return;
	}
	mySearch -> SearchFile("Expense.txt");
	XpensItem emptyExpense;
	cout << "Your total expense in " << m_months[month] << " is " << fixed << setprecision(2) << mySearch -> Month_total_CF(year, month, emptyExpense) << ".\n";
	
	mySearch -> SearchFile("Payment.txt");
	PaymentItem emptyPayment;
	cout << "Your total payment in " << m_months[month] << " is " << fixed << setprecision(2) << mySearch -> Month_total_CF(year, month, emptyPayment) << ".\n";
}

void ES::Budget()
{
	BudgetPlanner myPlanner;
	myPlanner.work_Budget();
}

void ES::ExpenseKeywordSearch()
{
	mySearch -> SearchFile("Expense.txt");
	XpensItem tempItem;
	string keyword;
	cout << "Key in your keyword:\n";
	cin >> keyword;
	mySearch -> SearchKeyword(keyword,tempItem);
	mySearch -> Print(tempItem);
}

void ES::PaymentKeywordSearch()
{
	mySearch -> SearchFile("Payment.txt");
	PaymentItem tempItem;
	string keyword;
	cout << "Key in your keyword:\n";
	cin >> keyword;
	mySearch -> SearchKeyword(keyword,tempItem);
	mySearch -> Print(tempItem);
}

void ES::showOverallReport()
{
	cout << "Your total payment is " << fixed << setprecision(2) << curRecord -> getTrace() -> gettotalPayment() << ".\n";
	cout << "Your total expense is " << fixed << setprecision(2) << curRecord -> getTrace() ->gettotalXpens() << ".\n";
	
}

void ES::showAllTransaction()
{
	int i = 0;
	streampos endpos;
	PaymentItem tempPayment;
	ifstream payfile("Payment.txt");
	payfile.seekg(-1,ios::end);
	endpos = payfile.tellg();
	payfile.seekg(ios::beg);
	cout << "Payment Transaction:\n";
	cout << "ID  |Name                            |Price     \n";
	cout << "    |Category            |Date       |";
	cout << "Payer                         \n";
	cout << "-------------------------------------------------------------------------------\n";
	while (payfile.tellg() < endpos){
		tempPayment.record_from_file(payfile,payfile.tellg());
		cout << std::left << setw(4);
		cout << ++i ;
		tempPayment.print();
	}
	i = 0;
	XpensItem tempExpense;
	ifstream Expensefile("Expense.txt");
	Expensefile.seekg(-1,ios::end);
	endpos = Expensefile.tellg();
	Expensefile.seekg(ios::beg);
	cout << "\nExpense Transaction:\n";
	cout << "ID  |Name                            |Price     \n";
	cout << "    |Category            |Date       |";
	cout << "Venue                         \n";
	cout << "-------------------------------------------------------------------------------\n";
	while (Expensefile.tellg() < endpos){
		tempExpense.record_from_file(Expensefile,Expensefile.tellg());
		cout << std::left << setw(4);
		cout << ++i ;
		tempExpense.print();
	}
}